
package com.zdkj.subway.stm.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zdkj.common.core.constant.CommonConstants;
import com.zdkj.common.security.util.ObjectUtils;
import com.zdkj.subway.stm.dto.in.SwStTvmCheckDetailDTO;
import com.zdkj.subway.stm.dto.in.SwStTvmSettleDTO;
import com.zdkj.subway.stm.dto.in.SwTvmSettleCycleCalculateDTO;
import com.zdkj.subway.stm.dto.in.SwTvmSettleSubmitDTO;
import com.zdkj.subway.stm.dto.out.SwStHandworkCleanRecordDTO;
import com.zdkj.subway.stm.dto.out.SwStTvmSupplementCurrencyDTO;
import com.zdkj.subway.stm.entity.*;
import com.zdkj.subway.stm.mapper.SwStTvmSettleMapper;
import com.zdkj.subway.stm.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * tvm结算
 *
 * @author songtuo
 * @date 2020-08-09 17:14:18
 */
@Service
@Slf4j
public class SwStTvmSettleServiceImpl extends ServiceImpl<SwStTvmSettleMapper, SwStTvmSettle> implements SwStTvmSettleService {

    @Autowired
    SwStTvmCheckDetailService stTvmCheckDetailService;

    @Autowired
    SwStTvmSupplementCurrencyService supplementCurrencyService;

    @Autowired
    SwStHandworkCleanRecordService cleanRecordService;

    @Autowired
    SwStTvmSettleDetailsService settleDetailsService;

    @Override
    @Transactional
    public boolean longCycleSellte(SwTvmSettleCycleCalculateDTO settleCycleCalculateDTO) {
        SwStTvmSettle swStTvmSettleObj = ObjectUtils.getDefaultObj(SwStTvmSettle.class);
        LocalDate startTime = settleCycleCalculateDTO.getStartTime();
        LocalDate endTime = settleCycleCalculateDTO.getEndTime();
        List<String> tvmcodeList = settleCycleCalculateDTO.getTvmcodeList();
        if (CollectionUtils.isEmpty(tvmcodeList)) {
            return false;
        }
        //1:合并tvm日清点数据 开始长周期合并 硬币回收箱1 硬币找零箱2 纸币回收箱3 纸币找零箱4 废钞箱5
        Map<String, Map<String, SwStTvmSettleDetails>> totalMap = new HashMap<>();
        for (String tvmCode : tvmcodeList) {
            Map<String, SwStTvmSettleDetails> countMap = new HashMap<>();
            //1:统计tvm日结详情数据
            mergeTvmDetailsData(countMap, startTime, endTime, tvmCode, swStTvmSettleObj);
            //2: key是tvmCode value是Map<String,SwStTvmSettleDetails>  key是钱箱类型+编号  value是当前要汇总的tvm收入
            totalMap.put(tvmCode, countMap);
        }
        //2:合并补币数据
        mergetSupplementData(startTime, endTime, tvmcodeList, swStTvmSettleObj, totalMap);
        //3:合并手工清出数据
        mergeHandClearData(startTime, endTime, tvmcodeList, swStTvmSettleObj, totalMap);

        //4:根据totalMap 创建tvm日计算主表和从表 并入库  保存主从表数据
        log.info("long Cycle Sellte data totalMap:{}", JSON.toJSONString(totalMap));
        saveMasterAndSlaveData(settleCycleCalculateDTO, swStTvmSettleObj, startTime, endTime, totalMap);
        return true;
    }

    @Override
    public boolean submit(SwTvmSettleSubmitDTO submitDTO) {
        List<Integer> ids = submitDTO.getIds();
        if (CollectionUtils.isEmpty(ids)) {
            return false;
        }
        for (Integer id : ids) {
            SwStTvmSettle stTvmSettle = getById(id);
            LocalDate startTime = stTvmSettle.getSellStartTime();
            LocalDate endTime = stTvmSettle.getSellEndTime();
            String tvmCode = stTvmSettle.getTvmCode();
            /**
             * 1:提交tvm日清点数据
             */
            List<SwStTvmCheckDetail> tvmCheckDetailList = stTvmCheckDetailService.list(new QueryWrapper<SwStTvmCheckDetail>().lambda().ge(SwStTvmCheckDetail::getRevenueTime, startTime).le(SwStTvmCheckDetail::getRevenueTime, endTime)
                    .eq(SwStTvmCheckDetail::getLineCode, stTvmSettle.getLineCode()).eq(SwStTvmCheckDetail::getStationCode, stTvmSettle.getStationCode())
                    .eq(SwStTvmCheckDetail::getTvmCode, tvmCode));
            tvmCheckDetailList.forEach(x -> x.setApprovalStatus(submitDTO.getStatus()));
            if (CollectionUtils.isNotEmpty(tvmCheckDetailList)) {
                stTvmCheckDetailService.updateBatchById(tvmCheckDetailList);
            }

            /**
             *2: 提交tvm补币数据
             */
            List<SwStTvmSupplementCurrency> checkDetailList = supplementCurrencyService.list(new QueryWrapper<SwStTvmSupplementCurrency>().lambda().ge(SwStTvmSupplementCurrency::getSupplementCurrencyTime, startTime)
                    .le(SwStTvmSupplementCurrency::getSupplementCurrencyTime, endTime)
                    .eq(SwStTvmSupplementCurrency::getLineCode, stTvmSettle.getLineCode()).eq(SwStTvmSupplementCurrency::getStationCode, stTvmSettle.getStationCode()));
            checkDetailList.forEach(x -> x.setApprovalStatus(submitDTO.getStatus()));
            if (CollectionUtils.isNotEmpty(checkDetailList)) {
                supplementCurrencyService.updateBatchById(checkDetailList);
            }

            /**
             * 3:提交tvm手动清出数据
             */
            List<SwStHandworkCleanRecord> cleanRecords = cleanRecordService.list(new QueryWrapper<SwStHandworkCleanRecord>().lambda().ge(SwStHandworkCleanRecord::getCleanTime, startTime)
                    .le(SwStHandworkCleanRecord::getCleanTime, endTime)
                    .eq(SwStHandworkCleanRecord::getLineCode, stTvmSettle.getLineCode()).eq(SwStHandworkCleanRecord::getStationCode, stTvmSettle.getStationCode()));
            cleanRecords.forEach(x -> x.setApprovalStatus(submitDTO.getStatus()));
            if (CollectionUtils.isNotEmpty(cleanRecords)) {
                cleanRecordService.updateBatchById(cleanRecords);
            }
            BeanUtil.copyProperties(submitDTO, stTvmSettle, CopyOptions.create().setIgnoreNullValue(true));
            stTvmSettle.setApprovalStatus(submitDTO.getStatus());
            updateById(stTvmSettle);
        }


        return true;
    }

    @Override
    public SwStTvmSettleDTO querySwTvmSettleDetails(Integer id) {
        SwStTvmSettleDTO swStTvmSettleDTO = new SwStTvmSettleDTO();
        SwStTvmSettle swStTvmSettle = getById(id);
        swStTvmSettleDTO.setSwStTvmSettle(swStTvmSettle);
        List<SwStTvmSettleDetails> details = settleDetailsService.list(new QueryWrapper<SwStTvmSettleDetails>().lambda().eq(SwStTvmSettleDetails::getRelationId, id));
        swStTvmSettleDTO.setDetails(details);
        return swStTvmSettleDTO;
    }

    private void saveMasterAndSlaveData(SwTvmSettleCycleCalculateDTO settleCycleCalculateDTO, SwStTvmSettle swStTvmSettleObj, LocalDate startTime, LocalDate endTime, Map<String, Map<String, SwStTvmSettleDetails>> totalMap) {
        for (String tvmCode : totalMap.keySet()) {
            Map<String, SwStTvmSettleDetails> tvmCountMap = totalMap.get(tvmCode);
            SwStTvmSettle swStTvmSettle = new SwStTvmSettle();
            //把一些属性
            BeanUtil.copyProperties(settleCycleCalculateDTO, swStTvmSettle, CopyOptions.create().setIgnoreNullValue(true));
            BeanUtil.copyProperties(swStTvmSettleObj, swStTvmSettle, CopyOptions.create().setIgnoreNullValue(true));
            swStTvmSettle.setSellStartTime(startTime);
            swStTvmSettle.setSellEndTime(endTime);
            swStTvmSettle.setSettlementTime(LocalDate.now());
            swStTvmSettle.setTvmCode(tvmCode);
            swStTvmSettle.setApprovalStatus(CommonConstants.STATUS_NORMAL);
            BigDecimal totalCheckAmount = new BigDecimal(0D);
            BigDecimal totalClearOutAmout = new BigDecimal(0D);
            BigDecimal totalsupplementAmount = new BigDecimal(0D);
            //公式  现金实收金额  钱箱清点金额-补币金额+手工清出
            Collection<SwStTvmSettleDetails> values = tvmCountMap.values();
            for (SwStTvmSettleDetails settleDetails : values) {
                if (settleDetails.getCheckAmount() != null) {
                    totalCheckAmount = totalCheckAmount.add(settleDetails.getCheckAmount());
                }
                if (settleDetails.getSupplementAmount() != null) {
                    totalsupplementAmount = totalsupplementAmount.add(settleDetails.getSupplementAmount());
                }
                if (settleDetails.getHandClearOutAmount() != null) {
                    totalClearOutAmout = totalClearOutAmout.add(settleDetails.getHandClearOutAmount());
                }
            }
            BigDecimal cashReceiptAmount = new BigDecimal(0D);
            swStTvmSettle.setCashReceiptAmount(cashReceiptAmount.add(totalCheckAmount).add(totalClearOutAmout).subtract(totalsupplementAmount));
            SwStTvmSettle stTvmSettle = getOne(new QueryWrapper<SwStTvmSettle>().lambda().eq(SwStTvmSettle::getSellStartTime, startTime)
                    .eq(SwStTvmSettle::getSellEndTime, endTime).eq(SwStTvmSettle::getTvmCode, tvmCode)
                    .eq(SwStTvmSettle::getStationCode, swStTvmSettleObj.getStationCode())
                    .eq(SwStTvmSettle::getLineCode, swStTvmSettleObj.getLineCode()));
            //进行覆盖
            if (null != stTvmSettle) {
                Integer id = stTvmSettle.getId();
                removeById(id);
                //级联删除
                settleDetailsService.remove(new QueryWrapper<SwStTvmSettleDetails>().lambda().eq(SwStTvmSettleDetails::getRelationId, id));
            }
            save(swStTvmSettle);
            values.forEach(x -> x.setRelationId(swStTvmSettle.getId()));
            settleDetailsService.saveBatch(values);
        }
    }


    private void mergeHandClearData(LocalDate startTime, LocalDate endTime, List<String> tvmcodeList, SwStTvmSettle swStTvmSettleObj, Map<String, Map<String, SwStTvmSettleDetails>> totalMap) {
        List<SwStHandworkCleanRecord> cleanRecords = cleanRecordService.list(new QueryWrapper<SwStHandworkCleanRecord>().lambda().ge(SwStHandworkCleanRecord::getCleanTime, startTime)
                .le(SwStHandworkCleanRecord::getCleanTime, endTime)
                .eq(SwStHandworkCleanRecord::getLineCode, swStTvmSettleObj.getLineCode()).eq(SwStHandworkCleanRecord::getStationCode, swStTvmSettleObj.getStationCode()));
        for (SwStHandworkCleanRecord cleanRecord : cleanRecords) {
            SwStHandworkCleanRecordDTO swStHandworkCleanRecordDTO = cleanRecordService.queryDetailsByid(cleanRecord.getId());
            List<SwStHandworkCleanRecordDetails> details = swStHandworkCleanRecordDTO.getDetails();
            List<SwStHandworkCleanRecordDetails> filterList = details.stream().filter(x -> tvmcodeList.contains(x.getTvmCode())).collect(Collectors.toList());
            for (SwStHandworkCleanRecordDetails recordDetails : filterList) {
                String tvmCashBoxType = recordDetails.getTvmCashBoxType();
                String tvmCashBoxNum = recordDetails.getTvmCashBoxNum();
                String tvmCode = recordDetails.getTvmCode();
                //1：判断当前的tvm钱箱有没有被统计过
                if (totalMap.get(tvmCode) == null) {
                    Map<String, SwStTvmSettleDetails> tvmCountMap = new HashMap<>();
                    SwStTvmSettleDetails settleDetails = new SwStTvmSettleDetails();
                    settleDetails.setCashboxCode(tvmCashBoxType);
                    settleDetails.setCashBoxType(tvmCashBoxNum);
                    settleDetails.setHandClearOutAmount(recordDetails.getClearOutAmount());
                    tvmCountMap.put(tvmCashBoxType + tvmCashBoxNum, settleDetails);
                    totalMap.put(tvmCode, tvmCountMap);
                } else {
                    Map<String, SwStTvmSettleDetails> tvmCountMap = totalMap.get(tvmCode);
                    //2: 判断当前的tvm钱箱有没有被统计过
                    if (tvmCountMap.get(tvmCashBoxType + tvmCashBoxNum) == null) {
                        SwStTvmSettleDetails settleDetails = new SwStTvmSettleDetails();
                        settleDetails.setCashboxCode(tvmCashBoxType);
                        settleDetails.setCashBoxType(tvmCashBoxNum);
                        settleDetails.setHandClearOutAmount(recordDetails.getClearOutAmount());
                        tvmCountMap.put(tvmCashBoxType + tvmCashBoxNum, settleDetails);
                    } else {
                        //3: 统计过的话那么进行数据的继续填充
                        SwStTvmSettleDetails settleDetails = tvmCountMap.get(tvmCashBoxType + tvmCashBoxNum);
                        settleDetails.setHandClearOutAmount(recordDetails.getClearOutAmount());
                    }
                }
            }
        }
    }

    /**
     * 合并补币数据
     *
     * @param startTime
     * @param endTime
     * @param tvmcodeList
     * @param swStTvmSettleObj
     * @param totalMap
     */
    private void mergetSupplementData(LocalDate startTime, LocalDate endTime, List<String> tvmcodeList, SwStTvmSettle swStTvmSettleObj, Map<String, Map<String, SwStTvmSettleDetails>> totalMap) {
        /**
         * 获取补币当天的数据
         */
        List<SwStTvmSupplementCurrency> checkDetailList = supplementCurrencyService.list(new QueryWrapper<SwStTvmSupplementCurrency>().lambda().ge(SwStTvmSupplementCurrency::getSupplementCurrencyTime, startTime)
                .le(SwStTvmSupplementCurrency::getSupplementCurrencyTime, endTime)
                .eq(SwStTvmSupplementCurrency::getLineCode, swStTvmSettleObj.getLineCode()).eq(SwStTvmSupplementCurrency::getStationCode, swStTvmSettleObj.getStationCode()));
        for (SwStTvmSupplementCurrency swStTvmSupplementCurrency : checkDetailList) {
            SwStTvmSupplementCurrencyDTO supplementCurrencyDTO = supplementCurrencyService.queryDetailsByid(swStTvmSupplementCurrency.getId());
            List<SwStTvmSupplementCurrencyDetails> details = supplementCurrencyDTO.getDetails();
            List<SwStTvmSupplementCurrencyDetails> filterList = details.stream().filter(x -> tvmcodeList.contains(x.getTvmCode())).collect(Collectors.toList());
            for (SwStTvmSupplementCurrencyDetails currencyDetails : filterList) {
                String tvmCashBoxType = currencyDetails.getTvmCashBoxType();
                String tvmCashBoxNum = currencyDetails.getTvmCashBoxNum();
                String tvmCode = currencyDetails.getTvmCode();
                //1：判断当前的tvm钱箱有没有被统计过
                if (totalMap.get(tvmCode) == null) {
                    Map<String, SwStTvmSettleDetails> tvmCountMap = new HashMap<>();
                    SwStTvmSettleDetails settleDetails = new SwStTvmSettleDetails();
                    settleDetails.setCashboxCode(tvmCashBoxType);
                    settleDetails.setCashBoxType(tvmCashBoxNum);
                    settleDetails.setSupplementAmount(currencyDetails.getSupplementAmount());
                    tvmCountMap.put(tvmCashBoxType + tvmCashBoxNum, settleDetails);
                    totalMap.put(tvmCode, tvmCountMap);
                } else {
                    Map<String, SwStTvmSettleDetails> tvmCountMap = totalMap.get(tvmCode);
                    //2: 判断当前的tvm钱箱有没有被统计过
                    if (tvmCountMap.get(tvmCashBoxType + tvmCashBoxNum) == null) {
                        SwStTvmSettleDetails settleDetails = new SwStTvmSettleDetails();
                        settleDetails.setCashboxCode(tvmCashBoxType);
                        settleDetails.setCashBoxType(tvmCashBoxNum);
                        settleDetails.setSupplementAmount(currencyDetails.getSupplementAmount());
                        tvmCountMap.put(tvmCashBoxType + tvmCashBoxNum, settleDetails);
                    } else {
                        //3: 统计过的话那么进行数据的继续填充
                        SwStTvmSettleDetails settleDetails = tvmCountMap.get(tvmCashBoxType + tvmCashBoxNum);
                        settleDetails.setSupplementAmount(currencyDetails.getSupplementAmount());
                    }
                }
            }
        }
    }


    private void mergeTvmDetailsData(Map<String, SwStTvmSettleDetails> countMap, LocalDate startTime, LocalDate endTime, String tvm, SwStTvmSettle swStTvmSettleObj) {
        List<SwStTvmCheckDetail> tvmCheckDetailList = stTvmCheckDetailService.list(new QueryWrapper<SwStTvmCheckDetail>().lambda().ge(SwStTvmCheckDetail::getRevenueTime, startTime).le(SwStTvmCheckDetail::getRevenueTime, endTime)
                .eq(SwStTvmCheckDetail::getLineCode, swStTvmSettleObj.getLineCode()).eq(SwStTvmCheckDetail::getStationCode, swStTvmSettleObj.getStationCode())
                .eq(SwStTvmCheckDetail::getTvmCode, tvm));
        for (SwStTvmCheckDetail tvmCheckDetail : tvmCheckDetailList) {
            //查询当前tvm的详情
            SwStTvmCheckDetailDTO swStTvmCheckDetailDTO = stTvmCheckDetailService.queryDetailsByid(tvmCheckDetail.getId(),"1");
            List<SwStTvmCheckDetailCoin> swStTvmCheckDetailCoins = swStTvmCheckDetailDTO.getSwStTvmCheckDetailCoins();
            for (SwStTvmCheckDetailCoin swStTvmCheckDetailCoin : swStTvmCheckDetailCoins) {
                createSellDetails(countMap, swStTvmCheckDetailCoin.getTvmCode(), swStTvmCheckDetailCoin.getCashboxCode(), swStTvmCheckDetailCoin.getRealAmount(), "1");
            }
            List<SwStTvmCheckDetailCoinChange> swStTvmCheckDetailCoinChanges = swStTvmCheckDetailDTO.getSwStTvmCheckDetailCoinChanges();
            for (SwStTvmCheckDetailCoinChange swStTvmCheckDetailCoinChange : swStTvmCheckDetailCoinChanges) {
                createSellDetails(countMap, swStTvmCheckDetailCoinChange.getTvmCode(), swStTvmCheckDetailCoinChange.getCashboxCode(), swStTvmCheckDetailCoinChange.getRealAmount(), "2");
            }
            List<SwStTvmCheckDetailPaper> swStTvmCheckDetailPapers = swStTvmCheckDetailDTO.getSwStTvmCheckDetailPapers();
            for (SwStTvmCheckDetailPaper swStTvmCheckDetailPaper : swStTvmCheckDetailPapers) {
                createSellDetails(countMap, swStTvmCheckDetailPaper.getTvmCode(), swStTvmCheckDetailPaper.getCashboxCode(), swStTvmCheckDetailPaper.getRealAmount(), "3");
            }
            List<SwStTvmCheckDetailPaperChange> swStTvmCheckDetailPaperChanges = swStTvmCheckDetailDTO.getSwStTvmCheckDetailPaperChanges();
            for (SwStTvmCheckDetailPaperChange swStTvmCheckDetailPaperChange : swStTvmCheckDetailPaperChanges) {
                createSellDetails(countMap, swStTvmCheckDetailPaperChange.getTvmCode(), swStTvmCheckDetailPaperChange.getCashboxCode(), swStTvmCheckDetailPaperChange.getRealAmount(), "4");
            }
            List<SwStTvmCheckDetailWaste> swStTvmCheckDetailWastes = swStTvmCheckDetailDTO.getSwStTvmCheckDetailWastes();
            for (SwStTvmCheckDetailWaste swStTvmCheckDetailWaste : swStTvmCheckDetailWastes) {
                createSellDetails(countMap, swStTvmCheckDetailWaste.getTvmCode(), swStTvmCheckDetailWaste.getCashboxCode(), swStTvmCheckDetailWaste.getRealAmount(), "5");
            }
        }
    }

    /**
     * 创建tvm合并详情
     *
     * @param countMap
     * @param tvmCode
     * @param cashboxCode
     * @param realAmount2
     * @param type
     */
    private void createSellDetails(Map<String, SwStTvmSettleDetails> countMap, String tvmCode, String cashboxCode, BigDecimal realAmount2, String type) {
        SwStTvmSettleDetails sellDetails = countMap.get(tvmCode + type + cashboxCode);
        BigDecimal realAmount = realAmount2;
        if (sellDetails == null) {
            SwStTvmSettleDetails settleDetails = new SwStTvmSettleDetails();
            settleDetails.setCashBoxType(type);
            settleDetails.setCashboxCode(cashboxCode);
            settleDetails.setCheckAmount(realAmount);
            countMap.put(type + cashboxCode, settleDetails);
        } else {
            sellDetails.setCheckAmount(sellDetails.getCheckAmount().add(realAmount));
        }
    }
}
